//
// Created by 15229 on 2022/11/19.
//

#ifndef _SYNCBARRIER_H
#define _SYNCBARRIER_H


#include <cstdint>
#include <cstdio>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <map>


///////////////////////////////////////// ConditionVariable /////////////////////////////////////////////////////////////
class ConditionVariable {
public:
    ConditionVariable(bool state = false);
    void close() noexcept;
    void block(int64_t timeoutMs = -1) noexcept;
    void open() noexcept;

private:
    std::mutex mMutex;
    std::condition_variable mConditionVariable;
    bool mCondition;
};

///////////////////////////////////////// CountDownLatch /////////////////////////////////////////////////////////////
class CountDownLatch {
public:
    CountDownLatch(uint32_t count);
    void countDown() noexcept;
    void await() noexcept;

private:
    std::mutex mMutex;
    std::condition_variable mConditionVariable;
    uint32_t mCount;
};

///////////////////////////////////////// BlockBarrier /////////////////////////////////////////////////////////////
class BlockBarrier {
public:
    BlockBarrier(uint32_t count, const char* name = nullptr);
    void setEnable(bool enable);
    void await(const char *what = nullptr);
    std::string toString(const char* what = nullptr);
private:
    const char* mName;

    std::mutex mMutex;
    std::condition_variable mCv;

    uint32_t mTargetNum;
    uint32_t mCount;
    bool mEnabled = true;
};

///////////////////////////////////////// StateBarrier /////////////////////////////////////////////////////////////

class StateBarrier {
    using TidStateMap = std::map<std::thread::id, int>;

public:
    StateBarrier(uint32_t count, const char* name = nullptr);

    void init();
    void mark();
    bool check();

    std::string toString(const char* what = nullptr);
private:
    const char* mName;
    const uint32_t mCount;
    std::mutex mMutex;
    TidStateMap mTidStateMap;
};


#endif //CPPTEXT_SYNCBARRIER_H
